package com.tengju.bff.interfaces.covercharge.service.bestsign;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tengju.bff.interfaces.covercharge.constant.CertificateApplyEnum;
import com.tengju.bff.interfaces.covercharge.constant.CoverChargeErrorCode;
import com.tengju.bff.interfaces.covercharge.constant.SignOnErrorCode;
import com.tengju.bff.interfaces.covercharge.entity.dto.HttpClientResponse;
import com.tengju.bff.interfaces.covercharge.handler.CoverChargeException;
import com.tengju.bff.interfaces.covercharge.service.bestsign.constant.BestSignBizReqUrlEnum;
import com.tengju.bff.interfaces.covercharge.service.bestsign.constant.BestSignConstant;
import com.tengju.bff.interfaces.covercharge.service.bestsign.util.HttpClientUtils;
import com.tengju.bff.interfaces.covercharge.service.bestsign.util.MD5HexUtils;
import com.tengju.bff.interfaces.covercharge.service.bestsign.util.RSAUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;


@Slf4j
@Component
public class BestSignClient {


    /**
     * 主账号测试：15168251536
     * 主账号线上：ssqianabm@163.com
     */
    @Value("${sign.best.account}")
    private String ACCOUNT;


    /**
     * 开发者ID测试1594179152011532807
     * 开发者ID线上1607403407014962649
     */
    @Value("${sign.best.developerId}")
    private String DEVELOPER_ID ;


    /**
     * 应用秘钥测试bfifwYyY8Ehvb8asBLJE91JVnRfF1lzr
     * 应用秘钥线上7Yh0gVTKrHEZL7ww4MEoILhZrqUBjdOM
     */
    @Value("${sign.best.accessKey}")
    private String ACCESS_KEY;

    /**
     * 开发者私钥
     */
    @Value("${sign.best.privateKey}")
    private String PRIVATE_KEY;

    //测试环境公钥：MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk8KTG1NFdACuEqI+/DIUaowgVn15g763/LsjaQnhkjxohTQk4OwZREzfwu7NJUupU6jyxz5Y+Wq1mAPhD5mZVeslK9hPV1jq9VP3FpWiiCbH4PAw+E6XjMa1DqWXXFkNI/65Z70U9Oxu06L2QQO5Yp5ygPe6OtjMA0N39SYu/pZfxB4mTk28ByfJPOlnXWWfO1LvhWpBqQMatE2XvERYEF9ZgfBrMKaK4enZOIu8vAjppP09ZNpx+TJF43eRZqQQnyjVhp7mpF99h/D9U0Yu0GhhfiSeyU8TOybS63PcH0sqjKcnW5rL5Pla+Ym1ihOMlKr71mhgq5AjJvWz2GdT4wIDAQAB
    //测试环境私钥：MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCTwpMbU0V0AK4Soj78MhRqjCBWfXmDvrf8uyNpCeGSPGiFNCTg7BlETN/C7s0lS6lTqPLHPlj5arWYA+EPmZlV6yUr2E9XWOr1U/cWlaKIJsfg8DD4TpeMxrUOpZdcWQ0j/rlnvRT07G7TovZBA7linnKA97o62MwDQ3f1Ji7+ll/EHiZOTbwHJ8k86WddZZ87Uu+FakGpAxq0TZe8RFgQX1mB8Gswporh6dk4i7y8COmk/T1k2nH5MkXjd5FmpBCfKNWGnuakX32H8P1TRi7QaGF+JJ7JTxM7JtLrc9wfSyqMpydbmsvk+Vr5ibWKE4yUqvvWaGCrkCMm9bPYZ1PjAgMBAAECggEAZhDjuN5efXDyzWBRjbeyLp84v0XRKFYXlXZXUXlH3dHoiQqp5sxv76QCdQ6rmnWXM3jiqwrAPxmc8rLLRhFdv+G8PXsf40BCnNAxP+KA8PeI3jJMQVlYih/Adaug0GObFiAgRi5wSXcAXySUYfiGmD7G7ZsxgvC6jA6Q0EBd+fEl57mt0nJebP6SB6Ov6ED8dNOSK9lVayLAMVOjXk3CLHN8AsV+2sETb2Mp/c3QZqdMXX6oDZQifUIWcJnqcqb53fgTFOq3xXiwD0Krce9LTPCny0RGeUd0Q+cXnp4hRFetzGf3lXtVmEsz4d0VJYpK+0XLLn+L66DDybXOqDrrMQKBgQD0PkExI8vNxAynmPdrdCD9i0hFszwk+dgerQq+2HwDglfYVYKcDr45irEovbvllaIMFA/GEP78P0iCLt/1eJPhXRBypfQWQTZ70eiUjwRu9OGpaCbubU/33jS/xzpdZDCpZQjx4j9IaRr5E1m2n1Q8zcUsitY3lG7268ztsTRXfwKBgQCa32IrH/z9Lvrhi8FDcl+Iq9KpjYge2mS5tOFxOTBMt0GCsu3lY5LB05fdqEpHy01YNNYi5c+J8MNS4pZwMPbzAUF96fzdE3TjOEYUB4Bdj8uXo2A47dxmOiBBgKOsV1J0MW+z2qyTtzf3oAm0u1ESJtL0G3of44S/pFI5Cf/VnQKBgQCEORuj1aQkfej35lizhEfD2t5CVXjO767vVHCHxrzETZDu3cP6ZgTXM90amDSbYnk6nrW3XUYdGslPKL83rZIpI++ekXblgWJUf9uwaQhWZR2xT2AcHXN4VYQq+lj/bBjn63l/MSNfOP9QLgiYVAMPc7o1lefIaQP1iswDNbaHUwKBgA7foTfvDIbsOh/rIhZuJ4qipcqu0wHTi5TiMDyFd4QGnX4F3R8InxGKVq1s+iVG+xibim0zkOj4fGm7ZSNFMJJJ7pY/II/CzJj90I0f404Y/z6C7DzLaz1OG8buqcllYX/TN50YRTayg+d+MTBwROrvW5ciBGqHmTomd9cOhMlpAoGBANcWxmps5gzPcq1gqw4HNDsfo/Rs6QRb/wlXa/rPoApzcIdKpQGYdyQunTxBCG39nqIWvzdIuJ7JEVV/axgHxZE6iI4VUpYmQFwFzb3h4URWtlwPo0neYcstpzos3CIdklz37VTXoKw1iPynqqPCofOxj8p0axySWKAfichjs7pN

    /**
     * 公有云Server的完整HOST，需要根据不同的环境配置
     * <p>
     * 测试环境（http）：http://openapi.bestsign.info/openapi/v2
     * 测试环境（https）：https://openapi.bestsign.info/openapi/v2
     * 正式环境（https）：https://openapi.bestsign.cn/openapi/v2
     */
    @Value("${sign.best.serverHost}")
    private String SERVER_HOST;




    /**
     * 处理上上签参数签名规则
     *
     * @param reqUrlEnum 业务请求
     * @param getBody    请求内容
     * @param postBody   请求内容
     * @return 结果
     */
    private String dealParamSign(BestSignBizReqUrlEnum reqUrlEnum, String getBody, String postBody) {
        //时间戳
        String timeStamp = RSAUtils.getTimeStamp();
        // 计算参数签名
        String paramsSign = RSAUtils.calcRsaSign(DEVELOPER_ID, PRIVATE_KEY, SERVER_HOST, reqUrlEnum.getMethod(),
                timeStamp, getBody, postBody);
        // 签名参数追加为url参数
        if (reqUrlEnum.isPost()) {
            return String.format(BestSignConstant.URL_SIGN_PARAMS, DEVELOPER_ID, timeStamp, paramsSign);
        } else {
            return String.format(BestSignConstant.URL_SIGN_PARAMS, DEVELOPER_ID, timeStamp, paramsSign) + "&" + getBody;
        }
    }

    /**
     * 上上签[post]服务请求
     *
     * @param reqUrlEnum 业务请求地址
     * @param request    入参请求
     * @param transId    业务流水号
     * @return 结果
     */
    public Map sendPost(BestSignBizReqUrlEnum reqUrlEnum, Object request, String transId) {
        String requestBody = JSON.toJSONString(request);
        //获取请求地址
        String reqUrl = SERVER_HOST + reqUrlEnum.getMethod() + dealParamSign(reqUrlEnum, null, requestBody);
        log.info("上上签[post]服务请求开始,类型:{},业务地址:{}，业务流水号：{}，入参:{}", reqUrlEnum.getMsg(), reqUrl, transId, requestBody);
        //发送请求
        HttpClientResponse response = HttpClientUtils.postJson(reqUrl, requestBody);
        if (Objects.isNull(response)) {
            log.error("上上签[post]服务请求通讯失败,类型:{},业务流水号：{}", reqUrlEnum.getMsg(), transId);
            throw new CoverChargeException(CoverChargeErrorCode.SYS_ERROR.getCode(), "上上签服务请求响应结果为空");
        }
        if (!response.isOk() || !response.contentIsNotNull()) {
            JSONObject jsonObject = HttpClientUtils.responseConvert(response.getErrMsg());
            String errCode = jsonObject.getString("errCode");
            String errMsg = jsonObject.getString("errMsg");
            log.error("上上签[post]服务请求响应异常,类型:{},业务流水号：{},response:{}", reqUrlEnum.getMsg(), transId, response);
            throw new CoverChargeException(errCode, errMsg);
        }
        log.info("上上签[post]服务请求结束,类型:{},业务流水号：{},response:{}", reqUrlEnum.getMsg(), transId, response);
        return JSON.parseObject(response.getContent(), HashMap.class);
    }


    /**
     * 上上签[get]服务请求
     *
     * @param reqUrlEnum 业务请求地址
     * @param request    入参请求
     * @param transId    业务流水号
     * @return 结果
     */
    public byte[] sendGet(BestSignBizReqUrlEnum reqUrlEnum, Object request, String transId) {
        String requestBody = String.valueOf(request);
        //获取请求地址
        String reqUrl = SERVER_HOST + reqUrlEnum.getMethod() + dealParamSign(reqUrlEnum, requestBody, null);
        log.info("上上签[get]服务请求开始,类型:{},业务地址:{}，业务流水号：{}，入参:{}", reqUrlEnum.getMsg(), reqUrl, transId, requestBody);
        //发送请求
        HttpClientResponse response = HttpClientUtils.sendHttpGet(reqUrl);
        if (Objects.isNull(response)) {
            log.error("上上签[get]服务请求通讯失败,类型:{},业务流水号：{}", reqUrlEnum.getMsg(), transId);
            throw new CoverChargeException(CoverChargeErrorCode.SYS_ERROR.getCode(), "上上签服务请求响应结果为空");
        }
        if (!response.isOk() || !response.contentIsNotNull()) {
            JSONObject jsonObject = HttpClientUtils.responseConvert(response.getErrMsg());
            String errCode = jsonObject.getString("errCode");
            String errMsg = jsonObject.getString("errMsg");
            log.error("上上签[get]服务请求响应异常,类型:{},业务流水号：{},errMsg:{}", reqUrlEnum.getMsg(), transId, errMsg);
            throw new CoverChargeException(errMsg);
        }
        log.info("上上签[post]服务请求结束,类型:{},业务流水号：{}", reqUrlEnum.getMsg(), transId);
        return response.getContentByte();
    }

    /**
     * 签名校验
     *
     * @param rtick 时间戳
     * @param sign  签名
     * @return 结果 是否一致
     */
    public boolean signVerify(String rtick, String sign, String jsonBody) {
        String retSign = MD5HexUtils.MD5Encode((MD5HexUtils.MD5Encode(jsonBody) + rtick + ACCESS_KEY));
        return sign.equals(retSign);
    }

    /**
     * 结果校验
     *
     * @param result 结果
     * @return data
     */
    public String checkResponse(Map result) {
        Object data = result.get("data");
        String errno = String.valueOf(result.get("errno"));
        String errMsg = String.valueOf(result.get("errmsg"));
        if (Objects.isNull(data)) {
            errMsg = this.codeConversion(errno, errMsg);
            throw new CoverChargeException(errno, errMsg);
        }
        //请求成功
        if (BestSignConstant.SUCCESS.equals(errno)) {
            return String.valueOf(data);
        } else {
            errMsg = this.codeConversion(errno, errMsg);
        }
        throw new CoverChargeException(errno, errMsg);
    }


    /**
     * code码转换
     */
    public String codeConversion(String errno, String msg) {
        //将240006单独分开
        if (errno.equals(String.valueOf(SignOnErrorCode.CERTIFICATION_CHECK_ERROR.getCode()))) {
            CertificateApplyEnum certificateApplyEnum = CertificateApplyEnum.getStatusDesc(msg);
            if (!Objects.isNull(certificateApplyEnum)) {
                msg = certificateApplyEnum.getDesc();
            }
        } else {
            SignOnErrorCode signOnErrorCode = SignOnErrorCode.getInstance(Integer.valueOf(errno));
            if (!Objects.isNull(signOnErrorCode)) {
                msg = signOnErrorCode.getMsg();
            }
        }
        return msg;
    }

    /**
     * 结果校验
     *
     * @param result 结果
     * @return data
     */
    public Boolean checkBooleanResponse(Map result) {
        Object data = result.get("data");
        String errno = String.valueOf(result.get("errno"));
        String errMsg = String.valueOf(result.get("errmsg"));
        if (Objects.isNull(data)) {
            throw new CoverChargeException(errno, errMsg);
        }
        //请求成功
        if (BestSignConstant.SUCCESS.equals(errno)) {
            return Boolean.TRUE;
        }
        throw new CoverChargeException(errno, errMsg);
    }


    public String getAccount () {
        return ACCOUNT;
    }
}
